#pragma once

#include <vulkan/vulkan.h>

#include <string>
#include <vector>
#include <iostream>
#include <unordered_map>
#include <memory>
#include <stdexcept>

namespace njm
{

    enum NjmImgFormat
    {
        NJM_IMG_FORMAT_UNKNOWN = 0,
        NJM_IMG_FORMAT_RGB8,
        NJM_IMG_FORMAT_RGBA8,
        NJM_IMG_FORMAT_RGB16F,
        NJM_IMG_FORMAT_RGBA16F,
        NJM_IMG_FORMAT_RGB32F,
        NJM_IMG_FORMAT_RGBA32F,
    };

    enum NjmImgExt
    {
        NJM_IMG_EXT_UNKNOWN = 0,
        NJM_IMG_EXT_PNG,
        NJM_IMG_EXT_JPG,
        NJM_IMG_EXT_BMP,
        NJM_IMG_EXT_TGA,
    };

    class NjmImg
    {
    private:
        

    public:
        using id_t = std::string;
        using Map = std::unordered_map<id_t, std::shared_ptr<NjmImg>>;

        std::string name{};
        NjmImgFormat format = NJM_IMG_FORMAT_UNKNOWN;
        int width = 0;
        int height = 0;
        int channels = 0;
        std::vector<unsigned char> data{};

        NjmImg() = default;
        NjmImg(const std::string& filepath);
        NjmImg(const std::string& name, const std::string& filepath);
        ~NjmImg() = default;
        
        NjmImg(const NjmImg &) = delete;
        NjmImg &operator=(const NjmImg &) = delete;
        NjmImg(NjmImg &&) = default;
        NjmImg &operator=(NjmImg &&) = default;

        static NjmImg createFromFile(const std::string& name, const std::string &filepath);
        static NjmImg createFromFile(const std::string &filepath);

        bool LoadFromFile(const std::string& name, const std::string &filepath);
        bool LoadFromFile(const std::string &filepath);
        bool SaveToFile(const std::string &filepath);

        static bool LoadFromFile(const std::string &filepath, std::vector<unsigned char> &buffer, int &width, int &height, int &channels);
        static bool SaveToFile(const std::string &filepath, const std::vector<unsigned char> &buffer, int width, int height, int channels);
    
        static NjmImgFormat GetImageFormat(int channels);
        static int GetChannels(NjmImgFormat image_format);
        static NjmImgExt GetImageExt(const std::string &path);
        static std::string GetImageExtStr(NjmImgExt ext);
        static VkFormat GetVkFormat(NjmImgFormat image_format);
        static NjmImgFormat GetNjmImgFormat(VkFormat vk_format);
    
        const VkExtent2D getVkExtent() const { return {static_cast<uint32_t>(width), static_cast<uint32_t>(height)}; }
        const VkFormat getVkFormat() const { return GetVkFormat(format); }
         
    };
}
